这篇文章是个总结,基于我在微博的工作和张俊林老师的演讲。个人以为微博的推荐在国内算是一个典型的应用。
我对于推荐系统也是刚刚入门的状态,文章有讲的不对的地方,敬请指正。
推荐系统架构
常见推荐场景
- 关系流 Feed 排序
- 热门流个性化排序
- 正文页推荐

分为两个部分,上面的是 在线推荐部分 ,下面的是 离线部分 。离线部分又分为两层,一层是 模型层 ,另一层是 存储层 。模型层负责离线模型训练和(常规模型)实时模型,这一层是直接和上面的在线推荐部分接触的,但是它们接触不到服务端和 SDK 发过来的原始日志。我们再往下走一层就是 存储层,包括离线日志的存储和实施用户行为的收集,处理后提供给上一层。
- 物料库
- 召回
- 排序
- 业务逻辑
架构技术栈
- 存储系统
- LevelDB
- Redis
- HBase
- MySQL
- 内容数据与模型
- 倒排
- 用户数据与模型
- 用户画像
- 短期模型
- ...
- 基础和平台
- 业务隔离
- 资源隔离
- ABTest
- 运维
- 扩容
- 干预平台
- 监控
- 追踪
- ...
模型

多路召回
根本要求是速度快1,兼顾用户兴趣,要快就没办法上复杂的模型
这一步我们会把大量的物料降到 \(10@ \sim 10^3\) 级别,然后做排序

排序
这里的模型在后文会讲,关键一点是要 准,因为数据量较少,可以部署复杂模型。
特征分类

产品策略

模型历史

所有排序模式的核心都是解决有效的 特征组合 问题。

传统模型:线性排序模型

特征组合要怎么组合?任意两个特征的组合,可以把一个特征组合当作一个新特征,但既然它是新特征,它也要学个权重,下图公式中标红的 \(w_{i,j}\) 就是这个特征组合的权重。
FM

上面模型的问题是特征组合的泛化能力弱,于是我们可以进一步对它进行如下修改。

我们把 \(w_{i,j}\) 换成 \(v_i\) 和 \(v_j\) 的点积
\(v_i\) 和 \(v_j\) 又是什么含义呢? \(v_i\) 的意思是:对于 \(x_i\) 这个特征来说它会学到一个 \(k\) 维的 embedding 向量,特征组合权重是通过两个单特征各自的 embedding 的内积呈现的,因为它内积完就是个数值,可以代表它的权重,这其实就是 FM 模型。

SVM 泛化能力弱,FM 的泛化能力强。
FFM
FFM 效果比 FM 好,但是问题在于,参数量太大。
FFM 是 FM 的一个特例,它更细致地刻画了这个特征。首先它做了任意两个特征组合,但是区别在于,怎么刻划这个特征? FM 只有一个向量,但 FFM 现在有两个向量,也就意味着同一个特征,要和不同的 fields 进行组合的时候,会用不同的 embedding 去组合,它的参数量更多。对于一个特征来说,原先是一个 vector,现在会拓成 F 个 vector,F 是特征 fields 的个数,只要有跟其它特征的任意组合,就有一个 vector 来代表,这就是 FFM 的基本思想。

对于 FFM 的某个特征来说,会构造 F 个 vector ,来和任意其他的 fields 组合的时候,各自用各自的。它有什么特点呢?首先, FFM 相对 FM 来说,参数量扩大了 F 倍,效果比 FM 好,但是要真的想把它用到现实场景中是有问题的,而问题同样在于参数量太大。参数量太大导致做起来特别耗内存,特别慢,所以我们的改进目标是把 FFM 模型的参数量降下来,并且效果又能达到 FFM 的效果。于是我们改了一个新模型,我把它叫 双线性 FFM 模型。
注意这里是针对某个特征,构造 F 个 vector,\(v_{i,j}\) 和任意其他的 fields 组合的时候有不同的妙用 不是直接分为 F 个域分别 embedding 这里可以参考美团的 这篇文章
双线性 FFM 模型
因为每个特征现在有 F 个 vector 来表示它的参数空间,每个特征都需要跟上 F 个 vector ,一般 CTR 任务中的特征数量是非常大的,所以 FFM 的参数量就异常地大。能不能把跟每个特征走的参数矩阵,抽出它们的共性,所有特征大家一起共享地来用这个参数?如果你一起用的话,就能够共享这个参数矩阵,你就能把参数量降下来,这就是我们讲的双线性 FFM 的核心思想。\(v_i, v_j\)还是跟 FM 一样,还是用一个 vector 来表达,但是把两个特征交互的信息放在共享参数里面去学,这就是双线性 FFM 的核心思想。





我们来估算一下,改进的双线性 FFM 模型,它的参数量跟 FFM 比是什么情况?如果说我们用 Criteo 这个 4500 万的数据集,它有 230 万个特征,39 个 Fields,假设 embedding size 是 10,如果用 FFM 就会有 8.97 亿的参数量,而用双线性 FFM,FM 部分是大概 2300 万的参数,刚才三个改进模型中,类型一 100 个参数,类型二 3900 个参数,类型三 15 万参数,与 FFM 相比,参数差了 38 倍,但性能两者是相当的,这就是这个模型的价值所在。
深度模型

所有的深度学习,做 CTR 的模型时都会有 DNN 的部分,没有例外。什么含义呢?特征输进去,然后把它转换成 embedding ,上面套两个隐层进行预测,这是所有模型公有的一部分。

我把现在这个深度 CTR 模型会分成了两大类。从结构来说,第一类我把它叫并行结构,它有 DNN 结构外的另外一个组件,我管它叫 FM Function,它捕捉特征的两两组合,两者关系看上去是个并行的,所以我把它叫并行结构。

除了并行还能怎么修改这个结构?可以把它搞成串行的,前面一样是 onehot 到 embedding 特征编码,然后用 FM Function 做二阶特征组合,上面套两个隐层做多阶特征捕获,这是串行结构。典型的模型包括:PNN、NFM、AFM 都属于这种结构。

第一条路线,提出新型的 FM Function,就是怎么能够设计一个新的 FM Function 结构,来更有效地 捕获二阶特征组合,比如说典型的模型包括 Wide&Deep,DeepFM,NeuralFFM 等,就是用来做这个的。
第二条演进路线,就是 显式地对二阶、三阶、四阶···\(K\)阶组合进行建模。目前的研究结论是这样的:对 CTR 捕获二、三、四阶都有正向收益,再捕获五阶以上就没什么用了。典型的代表模型是 DeepCross、xDeepFM。
并行系列

Wide & Deep 的结构是什么呢?实际上就是我画的并行结构,右边就是 DNN 部分,左边的 FM Function 用的是线性回归。我个人认为, Wide & Deep 是相对原始的模型, LR 有的问题它也有,特征组合需要人去设计,Wide & Deep 也有这样的问题。

我们可以改进一下。 DeepFM 模型,它相对 Wide & Deep 做出了什么改进呢?很简单,其实就是把 FM Function 的 LR 换成了 FM ,就能自动做特征组合了,这就是 DeepFM 。如果想部署深度模型,我建议可以考虑这个模型,这是目前效果最好的基准模型之一。而且我认为 DeepFM 是个目前技术发展阶段,完备的深度 CTR 模型。所谓完备,是指的里面的任意一个构件都有用,都不能少,但是如果再加新东西,感觉意义又没那么大,或者太复杂了工程化有难度。完备是从这个角度说的。
串行系列

Deep & Cross 用来做什么?显式地做高阶特征组合。就是说设计几层神经网络结构,每一层代表其不同阶的组合,最下面是二阶组合,再套一层,三阶组合,四阶组合,一层一层往上套,这就叫显式地捕获高阶特征组合,Deep & Cross 是最开始做这个的。

xDeepFM 是微软 2018 年发的一篇新论文,它是用来把二阶、三阶、四阶组合一层一层做出来,但无非它用的是类 CNN 的方式来做这个事的。这是第二个路线的两个代表。尽管这个符合模型发展趋势,我个人认为这种模型太复杂,真正部署上线成本比较高,不是优选方案。


总结

微博的物料库是百亿级别的↩